#ifndef __SHM__HPP__
#define __SHM__HPP__
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <unistd.h>
#include <cstdio>
#include <cerrno>
#include <iostream>
#include <string>
#include <cstring>
#define Creator 1
#define User 2
const int size = 4096;
const std::string static_path = "/home/ubuntu/Lhd/ShmTest";
const int Proj_id = 0x61;
class Shm
{
private:
    // 获取公共的key值
    key_t GetComKey()
    {
        key_t key = ftok(_pathname.c_str(), _proj_id);
        if (key < 0)
        {
            perror("ftok");
        }
        return key;
    }
    // 创建共享内存
    int GetShmHelper(key_t key, int size, int flag)
    {
        int shmid = shmget(key, size, flag);
        if (shmid < 0)
        {
            perror("shmget");
        }
        return shmid;
    }
    std::string GetWhoStr(int who)
    {
        if (who == Creator)
            return "Creator";
        else if (who == User)
            return "User";
        else
            return "None";
    }
    // 挂载共享内存
    void *AttachShm()
    {
        void *shmaddress = shmat(_shmid, nullptr, 0);
        if (shmaddress == nullptr)
        {
            perror("shmat");
            return nullptr;
        }
        std::cout << "who:" << GetWhoStr(_who) << "挂载成功" << std::endl;
        return shmaddress;
    }
    // 取消挂载
    void DeleShmAttach(void *shmaddress)
    {
        int n = shmdt(shmaddress);
        if (n < 0)
            perror("shmdt");
        std::cout << "who : " << GetWhoStr(_who) << "取消挂载done" << std::endl;
    }

public:
    Shm(const std::string &pathname, int proj_id, int who)
        : _pathname(pathname), _proj_id(proj_id), _who(who), _address(nullptr)
    {
        _key = GetComKey();
        if (_who == Creator)
            GetShmForCreate();
        else if (_who == User)
            GetShmForUsr();
        _address = AttachShm();
    }
    bool GetShmForCreate()
    {
        if (_who == Creator)
        {
            _shmid = GetShmHelper(_key, size, IPC_CREAT | IPC_EXCL | 0666);
            std::cout << "Shm create done..." << std::endl;
        }
        return _shmid >= 0 ? true : false;
    }
    bool GetShmForUsr()
    {
        if (_who == User)
        {
            _shmid = GetShmHelper(_key, size, IPC_CREAT | 0666);
        }
        return _shmid >= 0 ? true : false;
    }
    void *GetShmAddr()
    {
        return _address;
    }
    //清理shm
    void CleanShm()
    {
        if(_address)
        {
            memset(_address,'\0',size);
        }
    }
    ~Shm()
    {
        if (_address != nullptr)  DeleShmAttach(_address);
        if (_who == Creator)
        {
            int ret = shmctl(_shmid, IPC_RMID, nullptr);
            if (ret < 0)
                perror("shmctl");
        }
        std::cout << "Shm delete done..." << std::endl;
    }

private:
    key_t _key;
    int _shmid;
    std::string _pathname;
    int _proj_id;
    int _who;
    void *_address;
};

#endif